#include "config.h"

#include <gtest/gtest.h>

#include <memory>
#include <string>

using namespace cfg;

// 数组合并策略的覆盖测试
TEST(ArrayTest, ArrayMergeStrategies)
{
    // 工具：构造一对独立的 dst/src 根对象，互不共享可变数组
    auto make_roots = []()
    {
        // dst: { nums:[1,2,3], objs:[{"id":"a","v":1},{"id":"b","v":2}] }
        auto dst_nums = std::make_shared<Array>();
        dst_nums->items.push_back(int64_t{1});
        dst_nums->items.push_back(int64_t{2});
        dst_nums->items.push_back(int64_t{3});

        auto obj_a = std::make_shared<Object>();
        obj_a->props["id"] = std::string("a");
        obj_a->props["v"] = int64_t{1};
        auto obj_b = std::make_shared<Object>();
        obj_b->props["id"] = std::string("b");
        obj_b->props["v"] = int64_t{2};

        auto dst_objs = std::make_shared<Array>();
        dst_objs->items.push_back(std::shared_ptr<const Object>(obj_a));
        dst_objs->items.push_back(std::shared_ptr<const Object>(obj_b));

        cfg::Object dst_root;
        dst_root.props["nums"] = std::shared_ptr<const Array>(dst_nums);
        dst_root.props["objs"] = std::shared_ptr<const Array>(dst_objs);

        // src: { nums:[2,3,4], objs:[{"id":"b","v":20},{"id":"c","v":30}] }
        auto src_nums = std::make_shared<Array>();
        src_nums->items.push_back(int64_t{2});
        src_nums->items.push_back(int64_t{3});
        src_nums->items.push_back(int64_t{4});

        auto obj_b2 = std::make_shared<Object>();
        obj_b2->props["id"] = std::string("b");
        obj_b2->props["v"] = int64_t{20};
        auto obj_c = std::make_shared<Object>();
        obj_c->props["id"] = std::string("c");
        obj_c->props["v"] = int64_t{30};

        auto src_objs = std::make_shared<Array>();
        src_objs->items.push_back(std::shared_ptr<const Object>(obj_b2));
        src_objs->items.push_back(std::shared_ptr<const Object>(obj_c));

        cfg::Object src_root;
        src_root.props["nums"] = std::shared_ptr<const Array>(src_nums);
        src_root.props["objs"] = std::shared_ptr<const Array>(src_objs);

        return std::pair<cfg::Object, cfg::Object>{std::move(dst_root), std::move(src_root)};
    };

    // 1) 覆盖 Overwrite
    {
        auto [dst_root, src_root] = make_roots();
        Builder b;
        b.set_merge_strategy(MergeStrategy::Deep)
            .set_array_merge_strategy(ArrayMergeStrategy::Overwrite);
        b.merge_object(dst_root).merge_object(src_root);
        auto fr = b.freeze();
        ASSERT_TRUE(fr.has_value());
        View v(*fr);
        auto nums = v.lookup("nums");
        ASSERT_TRUE(nums.has_value());
        auto av = nums->array_view();
        ASSERT_TRUE(av.has_value());
        ASSERT_EQ(av->size(), 3u);
        EXPECT_EQ(std::get<int64_t>((*av)[0]), 2);
        EXPECT_EQ(std::get<int64_t>((*av)[1]), 3);
        EXPECT_EQ(std::get<int64_t>((*av)[2]), 4);
    }

    // 2) 追加 Append
    {
        auto [dst_root, src_root] = make_roots();
        Builder b;
        b.set_merge_strategy(MergeStrategy::Deep)
            .set_array_merge_strategy(ArrayMergeStrategy::Append);
        b.merge_object(dst_root).merge_object(src_root);
        auto fr = b.freeze();
        ASSERT_TRUE(fr.has_value());
        View v(*fr);
        auto nums = v.lookup("nums");
        auto av = nums->array_view();
        ASSERT_TRUE(av.has_value());
        ASSERT_EQ(av->size(), 6u);
        EXPECT_EQ(std::get<int64_t>((*av)[0]), 1);
        EXPECT_EQ(std::get<int64_t>((*av)[3]), 2);
        EXPECT_EQ(std::get<int64_t>((*av)[5]), 4);
    }

    // 3) 去重 Deduplicate
    {
        auto [dst_root, src_root] = make_roots();
        Builder b;
        b.set_merge_strategy(MergeStrategy::Deep)
            .set_array_merge_strategy(ArrayMergeStrategy::Deduplicate);
        b.merge_object(dst_root).merge_object(src_root);
        auto fr = b.freeze();
        ASSERT_TRUE(fr.has_value());
        View v(*fr);
        auto nums = v.lookup("nums");
        auto av = nums->array_view();
        ASSERT_TRUE(av.has_value());
        ASSERT_EQ(av->size(), 4u);
        EXPECT_EQ(std::get<int64_t>((*av)[0]), 1);
        EXPECT_EQ(std::get<int64_t>((*av)[1]), 2);
        EXPECT_EQ(std::get<int64_t>((*av)[2]), 3);
        EXPECT_EQ(std::get<int64_t>((*av)[3]), 4);
    }

    // 4) 按键合并 Keyed
    {
        auto [dst_root, src_root] = make_roots();
        Builder b;
        b.set_merge_strategy(MergeStrategy::Deep)
            .set_array_merge_strategy(ArrayMergeStrategy::Keyed)
            .set_array_merge_key("id");
        b.merge_object(dst_root).merge_object(src_root);
        auto fr = b.freeze();
        ASSERT_TRUE(fr.has_value());
        View v(*fr);
        auto objs = v.lookup("objs");
        auto av = objs->array_view();
        ASSERT_TRUE(av.has_value());
        ASSERT_EQ(av->size(), 3u); // b 被合并更新，c 追加

        // 校验 b 的 v 被更新为 20
        int b_index = -1;
        for (size_t i = 0; i < av->size(); ++i)
        {
            const Value & it = (*av)[i];
            auto pobj = std::get_if<std::shared_ptr<const Object>>(&it);
            if (pobj && *pobj)
            {
                View ov(*pobj);
                auto id = ov.lookup("id");
                if (id.has_value())
                {
                    auto s = id->get_string();
                    if (s.has_value() && *s == "b")
                    {
                        b_index = static_cast<int>(i);
                        break;
                    }
                }
            }
        }
        ASSERT_NE(b_index, -1);
        auto pobj = std::get<std::shared_ptr<const Object>>((*av)[b_index]);
        View bv(pobj);
        auto vfield = bv.lookup("v");
        ASSERT_TRUE(vfield.has_value());
        auto vi = vfield->get_int64();
        ASSERT_TRUE(vi.has_value());
        EXPECT_EQ(*vi, 20);
    }
}

// 数组合并策略：边界用例覆盖
TEST(ArrayTest, ArrayMergeStrategies_EdgeCases)
{
    // 1) 空数组与空数组合并（Append）
    {
        auto dst_nums = std::make_shared<Array>(); // 空
        auto src_nums = std::make_shared<Array>(); // 空
        Object dst_root;
        dst_root.props["nums"] = std::shared_ptr<const Array>(dst_nums);
        Object src_root;
        src_root.props["nums"] = std::shared_ptr<const Array>(src_nums);

        Builder b;
        b.set_merge_strategy(MergeStrategy::Deep)
            .set_array_merge_strategy(ArrayMergeStrategy::Append);
        b.merge_object(dst_root).merge_object(src_root);
        auto fr = b.freeze();
        ASSERT_TRUE(fr.has_value());
        View v(*fr);
        auto nums = v.lookup("nums");
        ASSERT_TRUE(nums.has_value());
        auto av = nums->array_view();
        ASSERT_TRUE(av.has_value());
        EXPECT_EQ(av->size(), 0u);
    }

    // 2) 目标为 nullptr，源为非空数组：任何策略等效覆盖
    {
        auto src_nums = std::make_shared<Array>();
        src_nums->items.push_back(int64_t{7});
        Object dst_root;
        dst_root.props["nums"] = std::shared_ptr<const Array>(); // nullptr
        Object src_root;
        src_root.props["nums"] = std::shared_ptr<const Array>(src_nums);

        // Append 策略
        {
            Builder b;
            b.set_merge_strategy(MergeStrategy::Deep)
                .set_array_merge_strategy(ArrayMergeStrategy::Append);
            b.merge_object(dst_root).merge_object(src_root);
            auto fr = b.freeze();
            ASSERT_TRUE(fr.has_value());
            View v(*fr);
            auto nums = v.lookup("nums");
            ASSERT_TRUE(nums.has_value());
            auto av = nums->array_view();
            ASSERT_TRUE(av.has_value());
            ASSERT_EQ(av->size(), 1u);
            EXPECT_EQ(std::get<int64_t>((*av)[0]), 7);
        }
        // Overwrite 策略
        {
            Builder b;
            b.set_merge_strategy(MergeStrategy::Deep)
                .set_array_merge_strategy(ArrayMergeStrategy::Overwrite);
            b.merge_object(dst_root).merge_object(src_root);
            auto fr = b.freeze();
            ASSERT_TRUE(fr.has_value());
            View v(*fr);
            auto nums = v.lookup("nums");
            ASSERT_TRUE(nums.has_value());
            auto av = nums->array_view();
            ASSERT_TRUE(av.has_value());
            ASSERT_EQ(av->size(), 1u);
            EXPECT_EQ(std::get<int64_t>((*av)[0]), 7);
        }
    }

    // 3) 类型不匹配在深合并下的冲突策略
    {
        // dst 为数组，src 为标量（字符串）
        auto dst_nums = std::make_shared<Array>();
        dst_nums->items.push_back(int64_t{1});
        Object dst_root;
        dst_root.props["nums"] = std::shared_ptr<const Array>(dst_nums);
        Object src_root;
        src_root.props["nums"] = std::string("not-array");

        // Overwrite：以源覆盖
        {
            Builder b;
            b.set_merge_strategy(MergeStrategy::Deep)
                .set_conflict_policy(ConflictPolicy::Overwrite)
                .set_array_merge_strategy(ArrayMergeStrategy::Append);
            b.merge_object(dst_root).merge_object(src_root);
            auto fr = b.freeze();
            ASSERT_TRUE(fr.has_value());
            View v(*fr);
            auto s = v.lookup("nums");
            ASSERT_TRUE(s.has_value());
            auto ss = s->get_string();
            ASSERT_TRUE(ss.has_value());
            EXPECT_EQ(*ss, "not-array");
        }

        // Keep：保留旧值（仍为数组）
        {
            Builder b;
            b.set_merge_strategy(MergeStrategy::Deep)
                .set_conflict_policy(ConflictPolicy::Keep)
                .set_array_merge_strategy(ArrayMergeStrategy::Append);
            b.merge_object(dst_root).merge_object(src_root);
            auto fr = b.freeze();
            ASSERT_TRUE(fr.has_value());
            View v(*fr);
            auto nums = v.lookup("nums");
            ASSERT_TRUE(nums.has_value());
            auto av = nums->array_view();
            ASSERT_TRUE(av.has_value());
            ASSERT_EQ(av->size(), 1u);
            EXPECT_EQ(std::get<int64_t>((*av)[0]), 1);
        }

        // Error：记录错误，保留旧值
        {
            Builder b;
            b.set_merge_strategy(MergeStrategy::Deep)
                .set_conflict_policy(ConflictPolicy::Error)
                .set_array_merge_strategy(ArrayMergeStrategy::Append);
            b.merge_object(dst_root).merge_object(src_root);
            auto fr = b.freeze();
            ASSERT_FALSE(fr.has_value());
        }
    }

    // 4) Keyed 降级：未设置键名/非对象元素/元素缺键
    {// 未设置键名：应退化为 Append
     {auto obj_a1 = std::make_shared<Object>();
    obj_a1->props["id"] = std::string("a");
    obj_a1->props["v"] = int64_t{1};
    auto obj_a2 = std::make_shared<Object>();
    obj_a2->props["id"] = std::string("a");
    obj_a2->props["v"] = int64_t{10};

    auto dst_objs = std::make_shared<Array>();
    dst_objs->items.push_back(std::shared_ptr<const Object>(obj_a1));
    auto src_objs = std::make_shared<Array>();
    src_objs->items.push_back(std::shared_ptr<const Object>(obj_a2));

    Object dst_root;
    dst_root.props["objs"] = std::shared_ptr<const Array>(dst_objs);
    Object src_root;
    src_root.props["objs"] = std::shared_ptr<const Array>(src_objs);

    Builder b;
    b.set_merge_strategy(MergeStrategy::Deep)
        .set_array_merge_strategy(ArrayMergeStrategy::Keyed); // 未设置 key
    b.merge_object(dst_root).merge_object(src_root);
    auto fr = b.freeze();
    ASSERT_TRUE(fr.has_value());
    View v(*fr);
    auto objs = v.lookup("objs");
    ASSERT_TRUE(objs.has_value());
    auto av = objs->array_view();
    ASSERT_TRUE(av.has_value());
    ASSERT_EQ(av->size(), 2u); // 退化为 Append

    // 统计 id == "a" 的数量应为 2
    int cnt_a = 0;
    for (const auto & it : *av)
    {
        auto pobj = std::get_if<std::shared_ptr<const Object>>(&it);
        if (pobj && *pobj)
        {
            View ov(*pobj);
            auto id = ov.lookup("id");
            if (id.has_value())
            {
                auto s = id->get_string();
                if (s.has_value() && *s == "a")
                    cnt_a++;
            }
        }
    }
    EXPECT_EQ(cnt_a, 2);
}

// 设置键名但存在非对象元素：这些元素直接追加
{
    auto dst_nums = std::make_shared<Array>();
    dst_nums->items.push_back(int64_t{1});
    auto src_nums = std::make_shared<Array>();
    src_nums->items.push_back(int64_t{2});
    Object dst_root;
    dst_root.props["nums"] = std::shared_ptr<const Array>(dst_nums);
    Object src_root;
    src_root.props["nums"] = std::shared_ptr<const Array>(src_nums);

    Builder b;
    b.set_merge_strategy(MergeStrategy::Deep)
        .set_array_merge_strategy(ArrayMergeStrategy::Keyed)
        .set_array_merge_key("id");
    b.merge_object(dst_root).merge_object(src_root);
    auto fr = b.freeze();
    ASSERT_TRUE(fr.has_value());
    View v(*fr);
    auto nums = v.lookup("nums");
    ASSERT_TRUE(nums.has_value());
    auto av = nums->array_view();
    ASSERT_TRUE(av.has_value());
    ASSERT_EQ(av->size(), 2u); // 直接追加
    EXPECT_EQ(std::get<int64_t>((*av)[0]), 1);
    EXPECT_EQ(std::get<int64_t>((*av)[1]), 2);
}

// 设置键名但元素缺失键：这些元素直接追加
{
    auto obj_a = std::make_shared<Object>();
    obj_a->props["id"] = std::string("a");
    obj_a->props["v"] = int64_t{1};
    auto obj_no_id = std::make_shared<Object>();
    obj_no_id->props["v"] = int64_t{2}; // 无 id

    auto dst_objs = std::make_shared<Array>();
    dst_objs->items.push_back(std::shared_ptr<const Object>(obj_a));
    auto src_objs = std::make_shared<Array>();
    src_objs->items.push_back(std::shared_ptr<const Object>(obj_no_id));

    Object dst_root;
    dst_root.props["objs"] = std::shared_ptr<const Array>(dst_objs);
    Object src_root;
    src_root.props["objs"] = std::shared_ptr<const Array>(src_objs);

    Builder b;
    b.set_merge_strategy(MergeStrategy::Deep)
        .set_array_merge_strategy(ArrayMergeStrategy::Keyed)
        .set_array_merge_key("id");
    b.merge_object(dst_root).merge_object(src_root);
    auto fr = b.freeze();
    ASSERT_TRUE(fr.has_value());
    View v(*fr);
    auto objs = v.lookup("objs");
    ASSERT_TRUE(objs.has_value());
    auto av = objs->array_view();
    ASSERT_TRUE(av.has_value());
    ASSERT_EQ(av->size(), 2u); // 缺失键名的对象被直接追加
}
}

// 5) Deduplicate 等价性：1 与 1.0 不相等；相同对象指针视为相等
{
    auto dst = std::make_shared<Array>();
    dst->items.push_back(int64_t{1});
    auto same_obj = std::make_shared<Object>();
    same_obj->props["x"] = int64_t{9};
    dst->items.push_back(std::shared_ptr<const Object>(same_obj));

    auto src = std::make_shared<Array>();
    src->items.push_back(double{1.0});                             // 与 1 不等
    src->items.push_back(std::shared_ptr<const Object>(same_obj)); // 同指针应视为相等

    Object d;
    d.props["a"] = std::shared_ptr<const Array>(dst);
    Object s;
    s.props["a"] = std::shared_ptr<const Array>(src);

    Builder b;
    b.set_merge_strategy(MergeStrategy::Deep)
        .set_array_merge_strategy(ArrayMergeStrategy::Deduplicate);
    b.merge_object(d).merge_object(s);
    auto fr = b.freeze();
    ASSERT_TRUE(fr.has_value());
    View v(*fr);
    auto a = v.lookup("a");
    auto av = a->array_view();
    ASSERT_TRUE(av.has_value());
    ASSERT_EQ(av->size(), 3u); // [1, obj, 1.0]
    EXPECT_EQ(std::get<int64_t>((*av)[0]), 1);
    // 中间为相同对象指针一次，不追加第二份
}
}